package edu.hm.compiler.interpreter.renamer;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import edu.hm.compiler.I18NCompiler;
import edu.hm.compiler.parser.grammar.predicate.Predicate;
import edu.hm.compiler.parser.grammar.predicate.PredicateSymbol;
import edu.hm.compiler.parser.grammar.term.Term;
import edu.hm.compiler.parser.grammar.term.TermCall;
import edu.hm.compiler.parser.grammar.term.TermVariable;
import edu.hm.compiler.parser.grammar.variable.Variable;

/**
 * @author Korny
 * @param <T>
 */
public abstract class Renamer< T >
{
    private final T                       ruleOrQuery;
    private final Map< String, Variable > renaming = new HashMap<>();

    /**
     * @param ruleOrQuery
     */
    public Renamer( final T ruleOrQuery )
    {
        if( ruleOrQuery == null )
            throw new IllegalArgumentException( I18NCompiler.getString("ArgumentNull") ); //$NON-NLS-1$
        this.ruleOrQuery = ruleOrQuery;
    }

    /**
     * @return
     */
    public abstract T rename();

    /**
     * @param predicate
     * @return
     */
    protected Predicate renamePredicate( final Predicate predicate )
    {
        if( predicate instanceof PredicateSymbol )
        {
            final List< Term > newTermlist = new ArrayList<>();
            for( final Term t: ( (PredicateSymbol) predicate ).getTermList() )
                newTermlist.add( this.renameTerm( t ) );

            return new PredicateSymbol( predicate.getSymbol(), newTermlist );
        }
        return predicate;
    }

    /**
     * @param term
     * @return
     */
    private Term renameTerm( final Term term )
    {
        if( term instanceof TermCall )
        {
            final List< Term > newTermList = new ArrayList<>();
            final TermCall termCall = (TermCall) term;
            for( final Term t: termCall.getTermList() )
                newTermList.add( this.renameTerm( t ) );
            return new TermCall( termCall.getSymbol(), newTermList );
        }
        else if( term instanceof TermVariable )
        {
            final TermVariable termVariable = (TermVariable) term;
            final String varId = termVariable.getVariable().getVarId();
            if( !this.renaming.containsKey( varId ) )
                this.renaming.put( varId, new Variable( varId ) );
            return new TermVariable( this.renaming.get( varId ) );

        }
        return term;
    }

    /**
     * @return
     */
    T getRuleOrQuery()
    {
        return this.ruleOrQuery;
    }

}